#ifndef _TYPES_H_
#define _TYPES_H_

/******************************************************************************
* SECTION: Type def
*******************************************************************************/
typedef int          boolean;
typedef uint16_t     flag16;

typedef enum nfs_file_type {
    NFS_REG_FILE,
    NFS_DIR
    // ,
    // NFS_SYM_LINK
} NFS_FILE_TYPE;



/******************************************************************************
* SECTION: Macro
*******************************************************************************/
#define TRUE                    1
#define FALSE                   0
#define UINT32_BITS             32
#define UINT8_BITS              8
 
#define NFS_SUPER_OFS           0
#define NFS_ROOT_INO            0



#define NFS_ERROR_NONE          0
#define NFS_ERROR_ACCESS        EACCES
#define NFS_ERROR_SEEK          ESPIPE     
#define NFS_ERROR_ISDIR         EISDIR
#define NFS_ERROR_NOSPACE       ENOSPC
#define NFS_ERROR_EXISTS        EEXIST
#define NFS_ERROR_NOTFOUND      ENOENT
#define NFS_ERROR_UNSUPPORTED   ENXIO
#define NFS_ERROR_IO            EIO     /* Error Input/Output */
#define NFS_ERROR_INVAL         EINVAL  /* Invalid Args */

#define NFS_MAX_FILE_NAME       128
#define NFS_INODE_PER_FILE      1   /* 每个文件用一个索引块 */
#define NFS_DATA_PER_FILE       8  /* 每个文件最多用16个物理块用于数据块 */
#define NFS_DATA_BLKS_PER_FILE  8   /* 每个文件使用8个数据块 */
#define NFS_DATA_BLKS_PRE       2   /* 每个数据块占多少个物理块 */

#define NFS_IOC_MAGIC           'S'
#define NFS_IOC_SEEK            _IO(NFS_IOC_MAGIC, 0)

#define NFS_FLAG_BUF_DIRTY      0x1
#define NFS_FLAG_BUF_OCCUPY     0x2



/******************************************************************************
* SECTION: Macro Function
*******************************************************************************/
#define NFS_IO_SZ()                     (nfs_super.sz_io)
#define NFS_BLK_SZ()                  (nfs_super.sz_block)
#define NFS_BLKS_SZ(blks)               (blks * NFS_BLK_SZ())
#define NFS_DISK_SZ()                   (nfs_super.sz_disk)
#define NFS_DRIVER()                    (nfs_super.driver_fd)

#define NFS_ROUND_DOWN(value, round)    (value % round == 0 ? value : (value / round) * round)
#define NFS_ROUND_UP(value, round)      (value % round == 0 ? value : (value / round + 1) * round)


#define NFS_ASSIGN_FNAME(pnfs_dentry, _fname)\ 
                                        memcpy(pnfs_dentry->fname, _fname, strlen(_fname))
// 定位第index个索引块在磁盘的位置
#define NFS_INO_OFS(index)                (nfs_super.inode_offset + index * NFS_BLK_SZ())
// 定位第index个数据块在磁盘的位置
#define NFS_DATA_OFS(index)               (nfs_super.data_offset + index * NFS_BLK_SZ())

#define NFS_IS_DIR(pinode)              (pinode->dentry->ftype == NFS_DIR)
#define NFS_IS_REG(pinode)              (pinode->dentry->ftype == NFS_REG_FILE)
// #define NFS_IS_SYM_LINK(pinode)         (pinode->dentry->ftype == NFS_SYM_LINK)



/******************************************************************************
* SECTION: FS Specific Structure - In memory structure 加载到内存进行使用时拓展的结构
*******************************************************************************/
struct nfs_dentry;
struct nfs_inode;
struct nfs_super;

struct custom_options {
	const char*        device;
	boolean            show_help;
};

/* 文件索引inode的数据结构 */
struct nfs_inode
{
    int                ino;                           /* 在inode位图中的下标 */
    int                size;                          /* 文件已占用空间 */
    char               target_path[NFS_MAX_FILE_NAME];/* store traget path when it is a symlink */
    int                dir_cnt;                          /* 该inode下所有的目录项的个数 */                      
    struct nfs_dentry* dentry;                        /* 指向该inode的dentry */ // 每个文件都有一个inode
    struct nfs_dentry* dentrys;                       /* 该inode下所有的目录项的头dentry指针 */
    uint8_t*           data[NFS_DATA_PER_FILE];           /* inode对应的文件的具体内容的指针*/
    // 目录文件的inode结构 用不到data成员 其磁盘内容是dentry数组 可以直接构建和写回 不用借助data存储 直接存储在对应的dentry结构即可
    // 普通文件的inode结构 需要用到data成员 用于在内存中缓存文件的内容 
    int                data_ptr[NFS_DATA_PER_FILE];
};  

// 众所周知，目录也是文件，存放的内容是该目录中所有文件的文件头的特殊文件
// 每个文件/目录都有路径
/* 路径entry的数据结构 */
struct nfs_dentry
{
    char               fname[NFS_MAX_FILE_NAME];  /* 绝对路径吗？ */
    struct nfs_dentry* parent;                        /* 父亲Inode的dentry */
    struct nfs_dentry* brother;                       /* 兄弟 */
    int                ino;                            /* 路径文件的索引的索引号 */ // 目录也是文件，也需要索引结构
    struct nfs_inode*  inode;                         /* 指向路径的索引inode */
    NFS_FILE_TYPE      ftype;                          /* 该路径是目录/文件/符号link */
};

/* 超级块的结构 */
struct nfs_super
{
    int                driver_fd;
    
    int                sz_io; // 每次对磁盘进行io的大小 磁盘块的大小 ddriver.iounit_size
    int                sz_disk; // 磁盘大小
    int                sz_block; // 逻辑块的大小

    int                sz_usage;
    
    int                max_ino; // 磁盘允许的创建的最大文件数量

    /* 超级块中关于索引位图块的结构 */
    uint8_t*           map_inode; // 索引位图块的指针
    int                map_inode_blks; // 索引位图块占的块数
    int                map_inode_offset; // 索引位图块的在整个磁盘的位置
    
    /* 超级块中关于数据位图块的结构 */ 
    uint8_t*           map_data; // 数据位图块的指针
    int                map_data_blks; // 数据位图块占的块数
    int                map_data_offset; // 数据位图块的在整个磁盘的位置


    /* 超级块中和数据块有关的结构 */
    int                data_offset; // 数据块在整个磁盘的位置

    /* 超级块中和索引块有关的结构 */
    int                inode_offset; // 索引块在整个磁盘的位置

    boolean            is_mounted; // 记录是否被挂载

    struct nfs_dentry* root_dentry; // 根目录dentry
};

/* new一个空的dentry，只设置fname 和 ftype*/
static inline struct nfs_dentry* new_dentry(char * fname, NFS_FILE_TYPE ftype) {
    struct nfs_dentry * dentry = (struct nfs_dentry *)malloc(sizeof(struct nfs_dentry));
    memset(dentry, 0, sizeof(struct nfs_dentry));
    NFS_ASSIGN_FNAME(dentry, fname);
    dentry->ftype   = ftype;
    dentry->ino     = -1;
    dentry->inode   = NULL;
    dentry->parent  = NULL;
    dentry->brother = NULL;                                    
}



/******************************************************************************
* SECTION: FS Specific Structure - Disk structure 静态的存在于磁盘中时的结构 作为和驱动读写打交道的接口
*******************************************************************************/
struct nfs_super_d
{
    uint32_t           magic_num;
    int                sz_usage;
    int                sz_block;
    
    int                max_ino;
    int                map_inode_blks;
    int                map_inode_offset;
    int                map_data_blks;
    int                map_data_offset;
    int                inode_offset;
    int                data_offset;
};

struct nfs_inode_d
{
    int                ino;                           /* 在inode位图中的下标 */
    int                size;                          /* 文件已占用空间 */
    char               target_path[NFS_MAX_FILE_NAME];/* store traget path when it is a symlink */
    int                dir_cnt;                        /* 如果是目录，表示为目录项的个数 */
    NFS_FILE_TYPE      ftype;                       /* inode对应的文件的类型*/
    int                data_ptr[NFS_DATA_PER_FILE]; /* 数据块号索引*/
    // 8个直接索引
};  

struct nfs_dentry_d
{
    char               fname[NFS_MAX_FILE_NAME];
    NFS_FILE_TYPE      ftype;
    int                ino;                           /* 指向的ino号 */
};  


#endif /* _TYPES_H_ */